///
//  AssetLoader v 1.0
//  Russell Lowke, March 1st 2011
//
//  Copyright (c) 2011 Lowke Media
//  see http://www.lowkemedia.com for more information
//
//  Permission is hereby granted, free of charge, to any person obtaining a 
//  copy of this software and associated documentation files (the "Software"), 
//  to deal in the Software without restriction, including without limitation 
//  the rights to use, copy, modify, merge, publish, distribute, sublicense, 
//  and/or sell copies of the Software, and to permit persons to whom the 
//  Software is furnished to do so, subject to the following conditions:
// 
//  The above copyright notice and this permission notice shall be included in 
//  all copies or substantial portions of the Software.
// 
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
//  IN THE SOFTWARE. 
//
//

// Starting to convert my AssetLoader AS3 package to JavaScript

function AssetLoader()
{   
    if (! AssetLoader.instance) {
        AssetLoader.instance = this;
    } else {
        throw new Error("AssetLoader is a singleton, it should never be created twice.\r" + 
                        "Use AssetLoader.instance to get a reference to AssetLoader.");
    }
    
    this.loaders = new Object();            // (object) loaders in use
    this.nLoaders = 0;                      // (uint) # of loaders remaining RENAME? _nLoadersRemaining
    this.nFilesTotal = 0;                   // (uint) # of loaders in this batch RENAME? _nLoadersTotal
    this.percentDone = NaN;                 // (number) percent loaded of nFilesTotal, NaN returned if idle
    
    ///
    // Loads an external file whose file type is determined by its file extension.
    // Once the asset has finished loading it is passed as the 1st argument to a function callback.
    //
    this.loadFile = function(url,           // (string) URL path to asset being loaded. File type is determined by the file extension suffix in the url. 
                                            //          Typical file types are .jpg, .mp3, .swf, and .xml. 
                            funct,          // (function) callback to which the loaded asset is passed once load has completed.
                            args,           // (array) array of args to be sent to the function along with the loaded asset.
                            obj)            // (object) object to send function callback to
    {
        // determine loader type using file suffix
        var suffix = AssetLoader.stripCGI(url);
        suffix = suffix.slice(suffix.lastIndexOf("."));
        var loaderType = AssetLoader.loaderType(suffix);
        
        if (! loaderType) {
            throw new Error("AssetLoader can't recognize loader type for use loading file with suffix of " + suffix + " and url " + url);
        }
        
        return this.load(url, loaderType, funct, args, obj);    
    }
    
    ///
    // Loads external file as a particular file type using an explicit loader.
    //
    this.load = function(url,               // (string) url URL path to file being loaded.
                         loaderType,        // (string) loader type to use when loading the asset
                         funct,             // (function) callback to which the loaded asset is passed once load has completed.
                         args,              // (array) array of args to be sent to the function along with the loaded asset.
                         obj)               // (object) object to send function callback to
    {
        // use appropriate loader
        var loader;
        switch (loaderType) {
            case AssetLoader.IMAGE:     loader = new LoadImage(url);            break;
            // case AssetLoader.SOUND:      loader = new LoadSound(url);        break;
            // case AssetLoader.DATA:       loader = new LoadData(url);         break;
            // case AssetLoader.XML:        loader = new LoadXML(url);          break;
            // case AssetLoader.BINARY:     loader = new LoadBinary(url);       break;
            // case AssetLoader.VIDEO:      loader = new LoadVideo(url);        break;
            
            default:
                throw new Error("AssetLoader can't recognize loader type \"" + loaderType + "\" for url " + url);
        }
        
        return this.loadUsing(loader, funct, args, obj);
    }
    
    
    ///
    // Uses a specific ILoad object to load a file.
    //
    this.loadUsing = function(loader,       // (Loader) loader to use when loading asset
                              funct,        // (function) callback to which the loaded asset is passed once load has completed.
                              args,         // (array) array of args to be sent to the function along with the loaded asset.
                              obj)          // (object) object to send function callback to
    {
        $(loader).one(LoadBase.ASSET_LOADED_EVENT, function(evt) {
            if (funct) {
                funct.apply(obj, [evt.asset].concat(args));
            }
        });
        this.addAssetLoader(loader);
        
        return loader;
    }

    ///
    // add a loader to this.loaders
    //
    this.addAssetLoader = function(loader)
    {   
        if (this.nFilesTotal == 0) {
            // dispatch immediate initial progress event
            $(this).trigger($.Event(AssetLoader.PROGRESS_EVENT), [0]);  // "0" progress, starting load
        }
        ++this.nFilesTotal;
            
        // keep _loader reference safe from garbage collection
        this.loaders[loader.id] = loader;
        ++this.nLoaders;
        loader.startLoad();
    }
    
    ///
    // this method is for internal use only. 
    // If you need to remove a loader use close().
    //
    // Removes exiting AssetLoader from _loaders queue.
    //
    this.removeAssetLoader = function(loader)
    {   
        loader.dispose();
        
        // and remove loader from _loaders
        this.loaders[loader.id] = null;
        delete this.loaders[loader.id];
        --this.nLoaders;
        
        // if all loaders finished
        if (this.nLoaders == 0) {
                
            // reset counters
            this.nFilesTotal  = 0;
            this.percentDone  = NaN;
            
            LogAs.debug("AssetLoader batch complete.", AssetLoader.DEBUG_BATCH_COMPLETE);
            $(this).trigger($.Event(AssetLoader.BATCH_COMPLETE_EVENT));
        }
    }
    
    this.whenDone = function(funct,     // (function) function to be called when batch finished loading
                             args,      // (array) array of args to be sent to function
                             obj)       // (object) object to send function callback to
    {
        if (this.nFilesTotal == 0) {
            // new DoLater(funct, args);    // SHOULD REALLY CALL funct ON NEXT IDLE
            if (funct) {
                funct.apply(obj, [args]);
            }
        } else {
            $(this).one(AssetLoader.BATCH_COMPLETE_EVENT, function() {
                if (funct) {
                    funct.apply(obj, [args]);
                }
            });
        }
    }
    
    
    this.toString = function() {
        return "[AssetLoader]";
    }
    
};
        
///
// Returns cleaned URL String stripped of any CGI "?" variables
//
AssetLoader.stripCGI = function(url)            // (string) URL String being stripped
{
    var index = url.indexOf('?');
    if (index > -1) {
        // strip out any "?" CGI data
        url = url.slice(0, index);
    }
    return url;
}

///
// Returns AssetLoader constant indicating file type. <code>null</code> returned if suffix not recognized.
//
AssetLoader.loaderType = function(suffix)       // (string) File suffix such as ".jpg" indicating file type.
{   
    suffix = suffix.toLowerCase();

    // find appropriate loader from suffix
    switch (suffix) {
                
        case ".aif": case ".aiff":          // Audio Interchange File Format 
        case ".mp3":                        // MPEG-1 Audio Layer 3
        case ".wav":                        // Waveform audio format
            return AssetLoader.SOUND;
                
        case ".bmp":                        // Bitmap image file format
        case ".png":                        // Portable Network Graphics
        case ".jpg": case ".jpeg":          // Joint Photographic Experts Group
            return AssetLoader.IMAGE;
                
        case ".html":                       // Hypertext Markup Language
        case ".txt": case ".text":          // Text (ASCI) data
            return AssetLoader.DATA;
                    
        case ".xml":                        // Extensible Markup Language
        case ".plist":                      // plist xml data
            return AssetLoader.XML;
                
        case ".bin":                        // binary
            return AssetLoader.BINARY;

        default:
            return null;            
    }
}

// events dispatched
AssetLoader.PROGRESS_EVENT          = "progress_event"
AssetLoader.BATCH_COMPLETE_EVENT    = "batch_complete_event"
    
// loader types
AssetLoader.IMAGE       = "image";          // .bmp, .png, .jpg, .jpeg
AssetLoader.SOUND       = "sound";          // .aif, .aiff, .mp3, .wav
AssetLoader.DATA        = "data";           // .html, .txt, .text
AssetLoader.XML         = "xml";            // .xml, .plist
AssetLoader.BINARY      = "binary";         // .bin


// error, warning and ifo IDs
// AssetLoader.WARNING_CANT_RECOGNIZE_FILE_TYPE    = 1000;
// AssetLoader.WARNING_CANT_RECOGNIZE_LOADER_TYPE  = 1001;
// AssetLoader.WARNING_FILE_NOT_FOUND              = 1002;
// AssetLoader.WARNING_FILE_CANT_LOAD              = 1003;
// AssetLoader.WARNING_CLASS_NOT_FOUND             = 1004;
// AssetLoader.WARNING_SECURITY_BREACH             = 1005;
// AssetLoader.WARNING_PARSE_ERROR                 = 1006;
// AssetLoader.WARNING_LOAD_TIMEOUT                = 1007;
// AssetLoader.INFO_LOADER_ISSUE                   = 1008;
AssetLoader.INFO_FILE_CLOSED                    = 1009;
AssetLoader.DEBUG_FILE_REQUESTED                = 1010;
AssetLoader.DEBUG_FILE_LOADED                   = 1011;
AssetLoader.DEBUG_BATCH_COMPLETE                = 1012;
